# -*- coding: utf-8 -*-
# @Time    : 2021/11/6 14:35
# @Author  : majw
# @Email   : 310916789@qq.com
# @File    : main.py
# @Software: PyCharm

import os
import logging
import yaml
import re
import time
from pyzabbix import ZabbixAPI, ZabbixAPIException
from git import Repo, exc
from concurrent.futures import ThreadPoolExecutor, as_completed
executor = ThreadPoolExecutor(max_workers=10)


def job_start(config):
    logging.info('----- JOB Start -----')
    # 用户名密码认证
    try:
        global zapi
        zapi = ZabbixAPI(config['zabbix']['url'])
        zapi.login(config['zabbix']['username'], config['zabbix']['password'])
    except ZabbixAPIException as zbx_err:
        logging.error('Zabbix {0} Login Failed: {1}.'.format(config['zabbix']['url'], zbx_err))
        job_end(1)

    # 获取待导出模板列表
    result = []
    try:
        result = zapi.template.get(output=['host'])
    except ZabbixAPIException as zbx_err:
        logging.error('Zabbix {0} Get Templates Failed: {1}.'.format(config['zabbix']['url'], zbx_err))
        job_end(1)
    
    if not result:
        logging.error('Zabbix {0} Get Templates Failed: Null Result. Please check permission with user {1}.'.format(config['zabbix']['url'], config['zabbix']['username']))
        job_end(1)

    # 检查导出目录是否存在，不存在则创建
    if not os.path.isdir(config['export_path']):
        os.makedirs(config['export_path'])
    os.chdir(config['export_path'])

    # 多线程导出模板
    total = len(result)
    index = 1
    try:
        task_list = [executor.submit(export_template, item) for item in result]
        for future in as_completed(task_list):
            data = future.result()
            if data['result']:
                logging.info('Template Export Success ({0}/{1}): {2}.'.format(index, total, data))
            else:
                logging.error('Template Export Failed ({0}/{1}): {2}.'.format(index, total, data))
            index += 1
    except Exception as e:
        logging.error(e)
        job_end(1)


def job_end(exitcode=0):
    logging.info('----- JOB End -----')
    exit(exitcode)


def export_template(template):
    # 定义模板导出文件名，默认为 模板名称.yaml
    filename = template['host'] + '.yaml'
    res = {
        'result': True,
        'file': filename
    }
    try:
        # 根据模板ID导出模板内容，格式为yaml
        result = zapi.configuration.export(format='yaml', options={'templates': [template['templateid']]})
        # 替换模板导出时间，否则Git会认为是不同的版本
        result = re.sub(r"date: '.*'", "date: '2021-01-01T00:00:00Z'", result)
        # 将模板内容写入文件
        with open(filename, 'w', encoding='utf-8') as f:
            f.write(result)
    except ZabbixAPIException as zbx_err:
        res['errmsg'] += zbx_err
    finally:
        return res


def push_to_git(path):
    os.chdir(path)
    commit_msg = 'Datetime: {0}'.format(time.strftime('%Y-%m-%d %H:%M:%S'))
    try:
        repo = Repo(path)
    except Exception as e:
        logging.error('Fetch Git Repo Failed: {0}'.format(e))
        job_end(1)

    git = repo.git
    # 拉取最新版本
    try:
        git.pull()
    except Exception as e:
        logging.error('Git pull Failed: {0}'.format(e))
        job_end(1)
    # 提交本地更新
    try:
        git.add('.')
        git.commit('-m', commit_msg)
    except Exception as e:
        logging.info('Git nothing to commit')
        job_end(0)
    # 上传本地更新
    try:
        git.push()
    except Exception as e:
        logging.error('Push to Git Failed: {0}'.format(e))
        job_end(1)


def main():
    # 定义日志文件路径及格式
    base_path = os.path.abspath(os.path.dirname(__file__))
    config_file = base_path + '/conf/config.yaml'
    log_path = base_path + '/logs'
    if not os.path.isdir(log_path):
        os.makedirs(log_path)
    logging.basicConfig(level=logging.INFO,
                        format='%(asctime)s %(name)s %(levelname)s %(message)s',
                        datefmt='%Y-%m-%d  %H:%M:%S %a',
                        filename=log_path + '/info.log')

    # 读取配置文件
    try:
        with open(config_file, 'r') as f:
            config = yaml.load(f.read(), Loader=yaml.FullLoader)
    except Exception as e:
        logging.error('Read Config Error: {0}.'.format(e))
        job_end(1)

    job_start(config)
    push_to_git(path=config['export_path'])
    job_end(0)


if __name__ == '__main__':
    main()
